/**
 * udp 实现局域网内的聊天室，针对机器而非针对人
 * server 监听 50000 端口，将接收到的数据转发给局域网内所有主机的60000端口
 *
 * 编译：gcc udp_broadcast.c -o udp_broadcast
 *
 * 运行：./udp_broadcast
 *
 * 测试  启动两个客户端
 * 一个连接50000端口，发消息                   nc -u 172.27.1.12 50000
 * 一个连接60000端口，接收其他人发送的消息     nc -u -l 172.27.1.12 60000
 *
 * 如果接收不到消息，有可能是网络防火墙问题，请关闭防火墙
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

int main(int argc, const char *argv[])
{
    int udp_socket;
    struct sockaddr_in myaddr,peeraddr;
    char buf[128] = {0};
    char sendbuf[128] = {0};
    ssize_t n;
    udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if(udp_socket < 0) {
        perror("fail to socket");
        exit(1);
    }

    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(50000);
    myaddr.sin_addr.s_addr = inet_addr("172.27.1.12");

    if(-1 == bind(udp_socket, (struct sockaddr*)&myaddr, sizeof(myaddr))) {
        perror("bind");
        exit(1);
    }

    socklen_t len = sizeof(peeraddr);
    while(1) {
        bzero(buf, sizeof(buf));
        if(-1 == recvfrom(udp_socket, buf, sizeof(buf), 0, (struct sockaddr*)&peeraddr, &len)) {
            perror("fail to recvfrom");
            exit(1);
        }
        bzero(sendbuf, sizeof(sendbuf));
        printf("peer ip:%s, port:%d, recv:%s\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
        sprintf(sendbuf, "peer ip:%s, port:%d, recv:%s\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port), buf);
        printf("sendbuf:%s\n", sendbuf);

        peeraddr.sin_family = AF_INET;
        peeraddr.sin_port = htons(60000);
        printf("receive: %s::::%s\n", buf,sendbuf);

        int i;
        for(i = 12; i < 255; i++) {
            peeraddr.sin_addr.s_addr = htonl((172<<24) + (27<<16) + (1<<8) + i);
            printf("sendto ip:%s\n", inet_ntoa(peeraddr.sin_addr));
            if(-1 == sendto(udp_socket, sendbuf, sizeof(sendbuf), 0, \
                        (struct sockaddr*)&peeraddr, sizeof(peeraddr))) {
                perror("fail to sendto");
                exit(1);
            }
        }
    }

    return 0;
}

